package com.dingwen.treasure.mybatisplus.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.script.JavaScriptEngine;
import cn.hutool.script.ScriptUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dingwen.treasure.base.enums.StatusEnum;
import com.dingwen.treasure.model.entity.mybatisplus.BusinessRule;
import com.dingwen.treasure.mybatisplus.service.BusinessRuleService;
import com.dingwen.treasure.mybatisplus.service.JavaScriptService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.script.CompiledScript;
import javax.script.ScriptException;
import java.util.Map;
import java.util.Set;

/**
 * 　JavaScriptComponent
 * 　@author dingwen
 * 　@date 2022/8/29
 */
@Slf4j
@Component
public class JavaScriptUtil {


    @Resource
    private BusinessRuleService businessRuleService;
    /**
     * 编译完成的Java Script 缓存
     */
    public static Map<Long, CompiledScript> COMPILED_SCRIPT_MAP;

    /**
     * 业务规则缓存
     */
    public static Map<Long, BusinessRule> BUSINESS_RULE_MAP;


    /**
     * JavaScriptEngine
     */
    public static JavaScriptEngine JAVA_SCRIPT_ENGINE = JavaScriptEngine.instance();


    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        LambdaQueryWrapper<BusinessRule> query = new LambdaQueryWrapper<BusinessRule>()
                .eq(BusinessRule::getRuleState, StatusEnum.NORMAL);
        int count = businessRuleService.count(query);
        COMPILED_SCRIPT_MAP = MapUtil.newConcurrentHashMap(count + 1);
        BUSINESS_RULE_MAP = MapUtil.newHashMap(count + 1);

        JAVA_SCRIPT_ENGINE.put("javaScriptService", SpringUtil.getBean(JavaScriptService.class));

        Set<String> allFieldNames = businessRuleService.getAllFieldNames();
        allFieldNames.forEach(fieldName -> {
            JAVA_SCRIPT_ENGINE.put(fieldName, "");
        });
    }


    /**
     * 刷新本地缓存
     *
     * @param ruleMap 规则配置
     */
    public void refreshLocalCache(Map<String, String> ruleMap) {
        BUSINESS_RULE_MAP.clear();
        ruleMap.forEach((k, v) -> {
            Long ruleId = Convert.toLong(k.substring(k.lastIndexOf(":") + 1));
            BusinessRule businessRule = JSONUtil.toBean(v, BusinessRule.class);
            BUSINESS_RULE_MAP.put(ruleId, businessRule);
            cacheCompiledScript(ruleId, businessRule.getRuleContent());
        });

    }

    /**
     * 缓存编译脚本
     *
     * @param ruleId 规则id
     * @param script 脚本
     */
    public void cacheCompiledScript(Long ruleId, String script) {
        try {
            CompiledScript compile = ScriptUtil.compile(JAVA_SCRIPT_ENGINE, script);
            COMPILED_SCRIPT_MAP.put(ruleId, compile);
        } catch (ScriptException e) {
            log.error("规则:{},JavaScript缓存编译脚本发生错误:{},内容:{}", ruleId, e.getMessage(), script);
        }
    }


}
